package zcatt.examples.java.demos;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/*
 * 本例演示了ForkJoinTask和ForkJoinPool的使用.
 * 素数的寻找.
 */
public class Snippet002_ForkJoinTask {

	public static void main(String[] args) {
		System.out.println("Snippet002_ForJoinTask start....");
		ForkJoinPool fjp = new ForkJoinPool(4);
		
		int start = 100000000;
		int len = 100;
		PrimeNumberTask task = new PrimeNumberTask(start, start+len);
		int[] res = fjp.invoke(task);
		
		StringBuffer s = new StringBuffer("result= ");
		for(int i:res)
		{
			s.append(i).append(", ");
		}

		System.out.println(s);
		System.out.println("Snippet002_ForJoinTask over");
		
	}


	public static class PrimeNumberTask extends RecursiveTask<int[]>
	{
		private static final long serialVersionUID = 1L;
		
		int start;
		int end;
		
		public PrimeNumberTask(int start, int end)
		{
			this.start = start;
			this.end = end;
		}

		boolean isPrimeNumber(int num)
		{
			System.out.println("thread("+Thread.currentThread().getId()+"), check "+num);
			if(num == 1 || num == 2)
				return false;
			
			try {
				Thread.sleep(100);
			}
			catch(Exception e)
			{				
			}
			
			for(int i = 2; i <= num/2; i++)
			{
				if((num/i) *i == num)
					return false;
			}
			return true;
		}
		
		@Override
		protected int[] compute() {
			//return computeSplitN();
			return computeSplit2();
		}
		
		//每次拆分, 取头4个
		int[] computeSplitN() {
			int[] res = null;
			
			assert start <= end;
			
			if(start == end)
			{
				if(isPrimeNumber(start))
				{
					res = new int[1];
					res[0] = start;
				}
				else
					res = new int[0];
			}
			else
			{
				ArrayList<PrimeNumberTask> tasks = new ArrayList<>();

				for(int i = 0; i<4; i++)
				{
					PrimeNumberTask sub = new PrimeNumberTask(start, start++);
					tasks.add(sub);
					
					if(start > end)
						break;
				}
				
				if(start <= end)
				{
					PrimeNumberTask sub = new PrimeNumberTask(start, end);
					tasks.add(sub);
				}
				
				//因为需要将子task的结果join起来, 此处只能invoke();
				invokeAll(tasks);
				
				res = new int[0];
				
				for(PrimeNumberTask e : tasks)
				{
					int[] subRes = e.join();
					
					//connect the sub
					int[] old = res;
					res = Arrays.copyOf(old, old.length + subRes.length);
					System.arraycopy(subRes, 0, res, old.length, subRes.length);					
				}
			}
			
			return res;
		}
		
		//二分法
		int[] computeSplit2() {
			int[] res=null;
			
			if(start == end)
			{
				if(isPrimeNumber(start))
				{
					res = new int[1];
					res[0] = start;
				}
				else
					res = new int[0];
			}
			else
			{
				int mid = (start + end) / 2;

				PrimeNumberTask sub1 = new PrimeNumberTask(start, mid);
				
				PrimeNumberTask sub2 = new PrimeNumberTask(mid+1, end);
				
				//因为需要将子task的结果join起来, 此处只能invoke();
				invokeAll(sub1, sub2);
				
				int[] res1 = sub1.join();
				int[] res2 = sub2.join();

				res = new int[res1.length + res2.length];
				
				System.arraycopy(res1, 0, res, 0, res1.length);
				System.arraycopy(res2, 0, res, res1.length, res2.length);					
			}
			
			return res;
		}
		

	}
}
